package com.link2room.rodimus.facade.impl;

import com.link2room.common.constant.DefaultValue;
import com.link2room.common.dto.result.base.BaseResultDto;
import com.link2room.common.enums.BaseSysExceptionEnum;
import com.link2room.common.exception.SysException;
import com.link2room.common.jpa.criteria.CriteriaUtil;
import com.link2room.common.jpa.result.QueryResult;
import com.link2room.common.service.ICommonService;
import com.link2room.common.util.ClassConverUtil;
import com.link2room.common.util.L2RAssert;
import com.link2room.common.util.StringUtil;
import com.link2room.rodimus.constant.GroupBuyingConstant;
import com.link2room.rodimus.dto.param.api.GroupBuyingTeamFindParamDto;
import com.link2room.rodimus.dto.param.base.GroupBuyingAutoCancelParamDto;
import com.link2room.rodimus.dto.param.base.GroupBuyingAutoRefundParamDto;
import com.link2room.rodimus.dto.param.base.GroupBuyingManualRefundParamDto;
import com.link2room.rodimus.dto.param.manager.GroupBuyingCreateManagerParamDto;
import com.link2room.rodimus.dto.param.manager.GroupBuyingListManagerParamDto;
import com.link2room.rodimus.dto.param.manager.GroupBuyingTeamUpdateParam;
import com.link2room.rodimus.dto.param.manager.GroupBuyingUpdateManagerParamDto;
import com.link2room.rodimus.dto.result.base.GroupBuyingBaseDto;
import com.link2room.rodimus.dto.result.base.GroupBuyingTeamDetailDto;
import com.link2room.rodimus.dto.result.base.GroupBuyingTeamDto;
import com.link2room.rodimus.dto.result.base.MallGoodBaseDto;
import com.link2room.rodimus.entity.GroupBuyingBaseEntity;
import com.link2room.rodimus.entity.GroupBuyingTeamDetailEntity;
import com.link2room.rodimus.entity.GroupBuyingTeamEntity;
import com.link2room.rodimus.entity.MallGoodBase;
import com.link2room.rodimus.facade.IGroupBuyingManagerFacadeService;
import com.link2room.rodimus.feign.trailbreaker.RefundFeignService;
import com.link2room.trailbreaker.dto.param.RefundParamDto;
import com.link2room.trailbreaker.dto.result.base.RefundResDto;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

import static com.link2room.enums.exception.RodimusSysExceptionEnum.*;


/**
 * Created by LN on 2017/12/5
 */
@Component("groupBuyingManagerFacadeService")
public class GroupBuyingManagerFacadeServiceImpl implements IGroupBuyingManagerFacadeService {
    @Resource
    private ICommonService commonService;
    @Resource
    private RefundFeignService refundFeignService;


    @Override
    public QueryResult<GroupBuyingBaseDto> listGroupBuyingBaseDto(GroupBuyingListManagerParamDto paramDto) throws Exception {
        String sortBy = paramDto.getSortBy();
        if (StringUtil.isNotBlank(sortBy)) {
            EnumSet<GroupBuyingBaseEntity.GroupBuyingBaseEntity_> enumSet = EnumSet.allOf(GroupBuyingBaseEntity.GroupBuyingBaseEntity_.class);
            String finalSortBy = sortBy;
            Optional<GroupBuyingBaseEntity.GroupBuyingBaseEntity_> e = enumSet.stream()
                    .filter(d -> d.toString().equals(finalSortBy))
                    .findAny();
            L2RAssert.isTrue(!e.isPresent(), new SysException(GROUP_BUYING_LIST_EROOR, "排序字段不存在"));
        } else {
            sortBy = GroupBuyingBaseEntity.BaseEntity_.id.toString();
        }
        String order = paramDto.getOrder();
        if (StringUtil.isNotBlank(order)) {
            L2RAssert.isTrue(!CriteriaUtil.DESC.equals(order) && !CriteriaUtil.ASC.equals(order), new SysException(GROUP_BUYING_LIST_EROOR, "[order] is required for ASC or DESC"));
        } else {
            order = CriteriaUtil.ASC;
        }

        HashMap<String, String> orderBy = new HashMap<>();
        orderBy.put(sortBy, order);
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGruopCode] is null.");
        GroupBuyingBaseEntity find = new GroupBuyingBaseEntity();
        find.setLhotelGroupCode(lhotelGroupCode);
        find.setIsHalt(paramDto.getIsHalt());
        find.setGoodCode(paramDto.getGoodCode());
        find.setIsHalt(paramDto.getIsHalt());
        QueryResult<GroupBuyingBaseEntity> qres = commonService.findAllEQ(GroupBuyingBaseEntity.class, find, paramDto.getCurrentPage(), paramDto.getPageSize(), orderBy, null);
        QueryResult<GroupBuyingBaseDto> resDtos = ClassConverUtil.copyQueryResultToDtoQueryResult(qres, GroupBuyingBaseDto.class, true);
        return resDtos;
    }

    @Override
    public GroupBuyingBaseDto groupBuyingBaseDto(GroupBuyingListManagerParamDto paramDto) throws Exception {
        String groupBuyingCode = paramDto.getGroupBuyingCode();
        L2RAssert.stringBlank(groupBuyingCode, "[groupBuyingCode] is required.");
        GroupBuyingBaseEntity find = new GroupBuyingBaseEntity();
        find.setLhotelGroupCode(paramDto.getLhotelGroupCode());
        find.setCode(paramDto.getGroupBuyingCode());
        GroupBuyingBaseEntity qres = commonService.findOneEQ(GroupBuyingBaseEntity.class, find);
        if (null != qres) {
            GroupBuyingBaseDto resDto = ClassConverUtil.copyProperties(qres, GroupBuyingBaseDto.class);
            MallGoodBase findGood = new MallGoodBase();
            findGood.setGoodCode(resDto.getGoodCode());
            MallGoodBase mallGoodEntity = commonService.findOneEQ(MallGoodBase.class, findGood);
            if (null != mallGoodEntity) {
                MallGoodBaseDto mallGood = ClassConverUtil.copyProperties(mallGoodEntity, MallGoodBaseDto.class);
                resDto.setMallGood(mallGood);
            }
            return resDto;
        } else {
            return null;
        }
    }

    @Override
    public void createGroupBuying(GroupBuyingCreateManagerParamDto paramDto) throws Exception {
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGroupCode] is null");
        String name = paramDto.getName();
        L2RAssert.stringBlank(name, "[name] is null.");
        nameCheck(lhotelGroupCode, name);
        String code = paramDto.getCode();
        L2RAssert.stringBlank(code, "[code] is null.");
        Integer duration = paramDto.getDuration();
        L2RAssert.numberNull(duration, "[duration] is null.");
        String goodCode = paramDto.getGoodCode();
        L2RAssert.stringBlank(goodCode, "[goodCode] is null.");
        Integer numMember = paramDto.getNumMember();
        L2RAssert.numberNull(numMember, "[numMember] is null.");
        BigDecimal captainPrice = paramDto.getCaptainPrice();
        checkPrice(captainPrice);
        BigDecimal teammatePrice = paramDto.getTeammatePrice();
        checkPrice(teammatePrice);

        //校验商品
        checkGoodBase(goodCode);
        Date startDate = paramDto.getStartDate();
        L2RAssert.isTrue(startDate == null, new SysException(GROUP_BUYING_CREATE_EROOR, "[startDate] is required."));
        Date endDate = paramDto.getEndDate();
        L2RAssert.isTrue(endDate == null, new SysException(GROUP_BUYING_CREATE_EROOR, "[endDate] is required."));
        L2RAssert.isTrue(endDate.before(startDate), new SysException(GROUP_BUYING_CREATE_EROOR, "[endDate] can not be before [startDate]."));

        GroupBuyingBaseEntity newEntity = new GroupBuyingBaseEntity();
        newEntity.setLhotelGroupCode(lhotelGroupCode);
        newEntity.setCode(code);
        long count = commonService.getCountAllEQ(GroupBuyingBaseEntity.class, newEntity, null);
        L2RAssert.isTrue(count > 0, new SysException(GROUP_BUYING_CREATE_EROOR, "[code] 重复"));

        newEntity.setLogo(paramDto.getLogo());
        newEntity.setDescript(paramDto.getDescript());
        newEntity.setDescriptM(paramDto.getDescriptM());
        newEntity.setContent(paramDto.getContent());
        newEntity.setNumMember(numMember);
        newEntity.setCaptainPrice(captainPrice);
        newEntity.setTeammatePrice(teammatePrice);
        newEntity.setDuration(duration);
        newEntity.setListOrder(paramDto.getListOrder());
        newEntity.setGoodCode(goodCode);
        newEntity.setEndDatetime(endDate);
        newEntity.setStartDatetime(startDate);
        newEntity.setLhotelGroupCode(lhotelGroupCode);
        newEntity.setName(name);
        newEntity.setIsAutoRefund(paramDto.getIsAutoRefund());
        commonService.save(newEntity);

    }

    private void nameCheck(String lhotelGroupCode, String name) throws Exception {
        GroupBuyingBaseEntity namCheck = new GroupBuyingBaseEntity();
        namCheck.setLhotelGroupCode(lhotelGroupCode);
        namCheck.setName(name);
        long count = commonService.getCountAllEQ(GroupBuyingBaseEntity.class, namCheck, null);
        L2RAssert.isTrue(count > 0, new SysException(GROUP_BUYING_CREATE_EROOR, "[name] 重复"));
    }

    @Override
    public void updateGroupBuying(GroupBuyingUpdateManagerParamDto paramDto) throws Exception {
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGroupCode] is null");
        String code = paramDto.getCode();
        L2RAssert.stringBlank(code, "[code] is null.");
        GroupBuyingBaseEntity findBase = new GroupBuyingBaseEntity();
        findBase.setCode(code);
        GroupBuyingBaseEntity groupBuyingBaseEntity = commonService.findOneEQ(GroupBuyingBaseEntity.class, findBase);
        L2RAssert.isTrue(null == groupBuyingBaseEntity, new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动不存在.[code] is " + code));

        String goodCode = paramDto.getGoodCode();
        checkGoodBase(goodCode);
        String name = paramDto.getName();
        L2RAssert.stringBlank(name, "[name] is null.");
        Integer duration = paramDto.getDuration();
        L2RAssert.numberNull(duration, "[duration] is null.");
        Integer numMember = paramDto.getNumMember();
        L2RAssert.numberNull(numMember, "[numMember] is null.");
        BigDecimal captainPrice = paramDto.getCaptainPrice();
        checkPrice(captainPrice);
        BigDecimal teammatePrice = paramDto.getTeammatePrice();
        checkPrice(teammatePrice);
        Date startDate = paramDto.getStartDate();
        L2RAssert.isTrue(startDate == null, new SysException(GROUP_BUYING_UPDATE_EROOR, "[startDate] is required."));
        Date endDate = paramDto.getEndDate();
        L2RAssert.isTrue(endDate == null, new SysException(GROUP_BUYING_UPDATE_EROOR, "[endDate] is required."));
        L2RAssert.isTrue(endDate.before(startDate), new SysException(GROUP_BUYING_UPDATE_EROOR, "[endDate] can not be before [startDate]."));

        //活动开始后.不能修改.
        boolean isStarted = false;
        isStarted = new Date().after(groupBuyingBaseEntity.getStartDatetime());
        if (isStarted) {
            L2RAssert.isTrue(!groupBuyingBaseEntity.getNumMember().equals(numMember), new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动已经开始,不能修改参团人数"));
            L2RAssert.isTrue(!groupBuyingBaseEntity.getDuration().equals(duration), new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动已经开始,不能修改持续时间"));
            L2RAssert.isTrue(groupBuyingBaseEntity.getStartDatetime().compareTo(startDate) != 0, new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动已经开始,不能修改活动开始时间"));
            L2RAssert.isTrue(groupBuyingBaseEntity.getCaptainPrice().compareTo(captainPrice)!= 0, new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动已经开始,不能修改价格"));
            L2RAssert.isTrue(groupBuyingBaseEntity.getTeammatePrice().compareTo(teammatePrice)!= 0, new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动已经开始,不能修改价格"));
            L2RAssert.isTrue(!groupBuyingBaseEntity.getGoodCode().equals(goodCode), new SysException(GROUP_BUYING_UPDATE_EROOR, "团购活动已经开始,不能修改商品"));
        } else {
            groupBuyingBaseEntity.setNumMember(numMember);
            groupBuyingBaseEntity.setCaptainPrice(captainPrice);
            groupBuyingBaseEntity.setTeammatePrice(teammatePrice);
            groupBuyingBaseEntity.setDuration(duration);
            groupBuyingBaseEntity.setEndDatetime(endDate);
            groupBuyingBaseEntity.setStartDatetime(startDate);
            groupBuyingBaseEntity.setListOrder(paramDto.getListOrder());
            groupBuyingBaseEntity.setLhotelGroupCode(paramDto.getLhotelGroupCode());
            groupBuyingBaseEntity.setName(name);
        }
        if (!name.equals(groupBuyingBaseEntity.getName())) {
            nameCheck(lhotelGroupCode, name);
        }
        groupBuyingBaseEntity.setIsHalt(paramDto.getIsHalt());
        groupBuyingBaseEntity.setIsAutoRefund(paramDto.getIsAutoRefund());
        groupBuyingBaseEntity.setName(name);
        groupBuyingBaseEntity.setLogo(paramDto.getLogo());
        groupBuyingBaseEntity.setDescript(paramDto.getDescript());
        groupBuyingBaseEntity.setDescriptM(paramDto.getDescriptM());
        groupBuyingBaseEntity.setContent(paramDto.getContent());
        commonService.merge(groupBuyingBaseEntity);
    }

    @Override
    public GroupBuyingTeamDto groupBuyingTeam(GroupBuyingTeamFindParamDto paramDto) throws Exception {
        String teamCode = paramDto.getTeamCode();
        L2RAssert.stringBlank(teamCode, "[teamCode] is null.");
        GroupBuyingTeamEntity findTeam = new GroupBuyingTeamEntity();
        findTeam.setTeamCode(teamCode);
        findTeam.setCaptainOpenid(paramDto.getCatpatinOpenid());
        findTeam.setCaptainNickName(paramDto.getCatpatinNickName());
        findTeam.setGroupBuyingCode(paramDto.getGroupBuyingCode());
        GroupBuyingTeamEntity teamEntity = commonService.findOneEQ(GroupBuyingTeamEntity.class, findTeam);
        if (teamEntity != null) {
            GroupBuyingTeamDto teamDto = ClassConverUtil.copyPropertiesToDto(teamEntity, GroupBuyingTeamDto.class, true);
            GroupBuyingTeamDetailEntity detailFind = new GroupBuyingTeamDetailEntity();
            detailFind.setTeamCode(teamCode);
            QueryResult<GroupBuyingTeamDetailEntity> qres = commonService.findAllEQ(GroupBuyingTeamDetailEntity.class, detailFind);
            if (CollectionUtils.isNotEmpty(qres.getResultlist())) {
                QueryResult<GroupBuyingTeamDetailDto> details = ClassConverUtil.copyQueryResultToDtoQueryResult(qres, GroupBuyingTeamDetailDto.class, true);
                teamDto.setGroupBuyingTeamDetails(details.getResultlist());
            }
            return teamDto;
        } else {
            return null;
        }
    }

    @Override
    public void updateGroupBuyingTeam(GroupBuyingTeamUpdateParam param) throws Exception {
        String teamCode = param.getTeamCode();
        L2RAssert.stringBlank(teamCode, "[teamCode] is required.");
        String sta = param.getSta();
        L2RAssert.stringBlank(sta, "[sta] is required.");
        String lhotelGroupCode = param.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGroupCode] is required.");
        GroupBuyingTeamEntity findTeam = new GroupBuyingTeamEntity();
        findTeam.setLhotelGroupCode(lhotelGroupCode);
        findTeam.setTeamCode(teamCode);
        GroupBuyingTeamEntity teamEntity = commonService.findOneEQ(GroupBuyingTeamEntity.class, findTeam);
        L2RAssert.isTrue(null == teamEntity, new SysException(MANUAL_UPDATE_TEAM_ERROR, "队伍不存在.[teamCode] is " + teamCode));
        teamEntity.setSta(sta);
        commonService.updateById(teamEntity);
    }

    @Override
    public void autoCancel(GroupBuyingAutoCancelParamDto autoCancelParamDto) throws Exception {
        String groupBuyingCode = autoCancelParamDto.getGroupBuyingCode();
        L2RAssert.stringBlank(groupBuyingCode, "[groupBuyingCode] is required.");
        String teamCode = autoCancelParamDto.getTeamCode();
        L2RAssert.stringBlank(teamCode, "[teamCode] is required.");
        String lhotelGroupCode = autoCancelParamDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGroupCode] is required.");
        GroupBuyingTeamEntity teamFind = new GroupBuyingTeamEntity();
        teamFind.setLhotelGroupCode(lhotelGroupCode);
        teamFind.setGroupBuyingCode(groupBuyingCode);
        teamFind.setTeamCode(teamCode);
        teamFind.setSta(GroupBuyingConstant.TEAM_STA.PENDING);
        GroupBuyingTeamEntity groupBuyingTeam = commonService.findOneEQ(GroupBuyingTeamEntity.class, teamFind);
        if (null == groupBuyingTeam) {
            return;
        }
        GroupBuyingBaseEntity findEntity = new GroupBuyingBaseEntity();
        findEntity.setCode(groupBuyingCode);
        GroupBuyingBaseEntity entity = commonService.findOneEQ(GroupBuyingBaseEntity.class, findEntity);
        if (null == entity) {
            return;
        }

        if (DefaultValue.T.equals(entity.getIsAutoRefund())) {
            GroupBuyingTeamDetailEntity detailFind = new GroupBuyingTeamDetailEntity();
            detailFind.setTeamCode(teamCode);
            detailFind.setLhotelGroupCode(lhotelGroupCode);
            QueryResult<GroupBuyingTeamDetailEntity> groupBuyingTeamDetails = commonService.findAllEQ(GroupBuyingTeamDetailEntity.class, detailFind);
            //不做自动退款.后台人工确认后发起退款操作
            groupBuyingTeamDetails.getResultlist()
                    .forEach(detail -> {
                        if (GroupBuyingConstant.TEAM_DETAIL_STA.PAID.equals(detail.getSta())) {
                            _autoRefund(detail);
                        } else if (GroupBuyingConstant.TEAM_DETAIL_STA.WAITING_PAY.equals(detail.getSta())) {
                            detail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.AUTO_CANCEL);
                            try {
                                commonService.merge(detail);
                            } catch (Exception ee) {
                                throw new SysException(BaseSysExceptionEnum.BASE_FUCATION_OPTION, ee);
                            }
                        }
                    });
        }
        groupBuyingTeam.setSta(GroupBuyingConstant.TEAM_STA.AUTO_CANCEL);
        commonService.merge(groupBuyingTeam);
    }


    private void _autoRefund(GroupBuyingTeamDetailEntity detail) {
        if (GroupBuyingConstant.TEAM_DETAIL_STA.PAID.equals(detail.getSta())) {
            RefundParamDto paramDto = new RefundParamDto();
            paramDto.setIsFullyRefund(DefaultValue.T);
            paramDto.setOrderNo(detail.getOrderNo());
            try {
                refundFeignService.refund(paramDto);
                detail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.AUTO_REFUND);
                commonService.merge(detail);
            } catch (Exception e) {
                detail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.AUTO_REFUND_ERROR);
                try {
                    commonService.merge(detail);
                } catch (Exception ee) {
                    throw new SysException(BaseSysExceptionEnum.BASE_FUCATION_OPTION, ee);
                }
            }
        }
    }

    @Override
    public void autoRefund(GroupBuyingAutoRefundParamDto paramDto) throws Exception {
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGroupCode] is required.");
        String teamCode = paramDto.getTeamCode();
        L2RAssert.stringBlank(teamCode, "[teamCode] is required.");
        String orderNo = paramDto.getOrderNo();
        L2RAssert.stringBlank(orderNo, "[orderNo] is required.");
        GroupBuyingTeamDetailEntity detailFind = new GroupBuyingTeamDetailEntity();
        detailFind.setTeamCode(teamCode);
        detailFind.setLhotelGroupCode(lhotelGroupCode);
        detailFind.setOrderNo(orderNo);
        GroupBuyingTeamDetailEntity detail = commonService.findOneEQ(GroupBuyingTeamDetailEntity.class, detailFind);
        if (null == detail) {
            return;
        }
        _autoRefund(detail);
    }

    @Override
    public void manualRefund(GroupBuyingManualRefundParamDto paramDto) throws Exception {
        String teamCode = paramDto.getTeamCode();
        L2RAssert.stringBlank(teamCode, "[teamCode] is required.");
        String orderNo = paramDto.getOrderNo();
        L2RAssert.stringBlank(orderNo, "[orderNo] is required.");
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        GroupBuyingTeamDetailEntity teamDetailFind = new GroupBuyingTeamDetailEntity();
        teamDetailFind.setOrderNo(orderNo);
        teamDetailFind.setLhotelGroupCode(lhotelGroupCode);
        teamDetailFind.setTeamCode(teamCode);
        GroupBuyingTeamDetailEntity teamDetail = commonService.findOneEQ(GroupBuyingTeamDetailEntity.class, teamDetailFind);
        L2RAssert.isTrue(null == teamDetail, new SysException(MANUAL_REFUND_EROOR, "订单不存在."));
        RefundParamDto refundParamDto = new RefundParamDto();
        refundParamDto.setOrderNo(orderNo);
        refundParamDto.setIsFullyRefund(DefaultValue.T);
        BaseResultDto<RefundResDto> refundRes = refundFeignService.refund(refundParamDto);
        if (DefaultValue.F.equals(refundRes.getResultInfo().getThirdResultCode())) {
            teamDetail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.MANUAL_REFUND_ERROR);
        } else {
            teamDetail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.MANUAL_REFUND);
        }

        commonService.merge(teamDetail);


    }

    private void checkPrice(BigDecimal price) {
        L2RAssert.isTrue(price == null, new SysException(GROUP_BUYING_CREATE_EROOR, "价格字段为空"));
        L2RAssert.isTrue(BigDecimal.ZERO.compareTo(price) > 0, new SysException(GROUP_BUYING_CREATE_EROOR, "价格不能小于零"));
    }

    private void checkGoodBase(String goodCode) throws Exception {
        MallGoodBase find = new MallGoodBase();
        find.setGoodCode(goodCode);
        MallGoodBase qres = commonService.findOneEQ(MallGoodBase.class, find);
        L2RAssert.isTrue(qres == null, new SysException(GROUP_BUYING_CREATE_EROOR, "商品不存在.[goodCode] is " + goodCode));
    }

}
